<template>
	<div id="content">
		<div class="list" ref="chatContainer" v-loading="isList">
			<div class="l-item" v-for="(item, index) in list" :key="index">
				<div class="l-item-right">
					<div class="l-ask">
						<div class="l-a-ask"> {{ item.ask }}</div>
					</div>
					<div class="l-a-img">S</div>
				</div>
				<div class="l-frame-left">
					<div class="l-item-left">
						<el-image class="l-img" src="/images/man.png" fit="contain" />
						<div class="l-answer">
							<div class="loader" v-if="!item.answer"></div>
							<div v-else v-html="getAnwser(item.answer)"></div>
							<div class="bottom" v-show="item.list.length">
								<span>引用</span>
								<div class="line"></div>
							</div>
							<div class="l-file" v-show="item.list.length">
								<div class="f-list" v-for="(file, index) in item.list" :key="index">
									<el-popover
										popper-style="padding:0px"
										placement="top"
										width="350"
										trigger="hover"
										>
										<div class="f-list-content popover-title">
											<el-image class="f-l-img" src="/images/pdf.png" fit="contain" />
											<span>{{ file.document_name }}</span>
										</div>
										<div class="popover-content">
											<div class="f-l-position">
												<div class="f-l-position-container">
													<span class="f-l-icon">#</span>
													<span>{{file.position}}</span>
												</div>
											</div>
											<div class="f-l-text">
												<span v-html="getFileContent(file.content)"></span>
											</div>
										</div>
										<template #reference>
											<div class="f-list-content">
												<el-image class="f-l-img" src="/images/pdf.png" fit="contain" />
												<span>{{ file.document_name }}</span>
											</div>
										</template>
									</el-popover>
								</div>
							</div>
						</div>
					</div>
					<div class="l-tip" v-show="item.latency != '0'">
						<span>耗时 </span>
						<span>{{ item.latency ? Number(item.latency).toFixed(2) : toHHmmss(item.created_at) }}</span>
						<span> 秒</span>
						<span>花费 Token </span>
						<span> {{ item.total_tokens }} </span>
						<span>.</span>
					</div>
				</div>
			</div>
		</div>
		<div class="ask">
			<input type="text" ref="refInput" :disabled="isAsking" v-model="ask" @keyup.enter="onSend">
			<div class="send" @click="onSend" v-show="!isAsking">
				<el-icon>
					<Top />
				</el-icon>
			</div>
		</div>
	</div>
</template>
<script setup lang="ts">
import { service } from '/@/cool';
import { reactive, onMounted, ref, nextTick, unref } from 'vue';
import { useRoute } from "vue-router"
import { wholeToParse } from "/@/utils/tools";
const route = useRoute();
let ask = ref("");
let isAsking = ref(false);
let isList = ref(false)
let strFirstId = ref('');
let commTip = '你的提问暂时还没找到答案，请完善你的问题。'
// 时间转分秒
function toHHmmss(date: number) {
	let time: string;
	let minutes = parseInt(((date % (1000 * 60 * 60)) / (1000 * 60)).toString());
	let seconds = (date % (1000 * 60)) / 1000;
	time = (minutes < 10 ? ('0' + minutes) : minutes) + ':' + (seconds < 10 ? ('0' + seconds) : seconds);
	return time;
}
// 滚动至底部
interface Scroll {
	scrollTop: number,
	scrollHeight: number
}
const chatContainer = ref(null);
function scrollToBottom() {
	nextTick(() => {
		if (chatContainer.value) {
			const scrollContainer: Scroll = chatContainer.value;
			scrollContainer.scrollTop = scrollContainer.scrollHeight;
		}
	});
}
// 文本框获取焦点
const refInput = ref();
const getFocus = () => {
	nextTick(() => {
		if(refInput){
			refInput.value.focus();
		}
	})
}
// 返回内容处理
interface Document {
	document_name: string
}
interface List {
	ask: string,
	answer: string,
	list: Array<Document>,
	latency: string,
	total_tokens: string,
	created_at: number
}
let list: Array<List> = reactive([
	// {
	//     ask: '测试下',
	//     answer: '...',
	//     list: [{
	//         document_name: "文档.pdf"
	//     }],
	//     latency: '654.5678987',
	//     total_tokens: '0',
	//     created_at:0
	// }
]);
// 根据查询条件，获取对应记录
async function getList(id: any, type: any) {
	isList.value = true;
	await service.base.open.messages({
		type: type,
		conversation_id: id,
		user: "suguoyuan",
		limit: 20
	}).then(data => {
		isList.value = false;
		let res = JSON.parse(data).data;
		strFirstId.value = res[0]?.conversation_id,
			res.forEach((item: any) => {
				let obj: List = {
					ask: item.query,
					answer: item.answer?item.answer: commTip,
					list: item.retriever_resources,
					latency: '',
					total_tokens: '',
					created_at: item.created_at
				}
				list.push(obj);
			})
		scrollToBottom();
	})
}
//获取引用弹出窗内容
const getFileContent=(content: any)=> {
	return content.replace(/\r\n|\n/g, '<br/>');
}
onMounted(() => {
	scrollToBottom();
	getFocus();
	console.log('--开始更新--')
	getList(route.query.id, route.query.type)
});
const getAnwser=(value)=>{
	return value.replace(/\r\n|\n/g,"<br/>");
}
// 发送请求获取数据
async function onSend() {
	isAsking.value = true;
	scrollToBottom();
	let item: List = {
		ask: ask.value,
		answer: '',
		list: [],
		latency: '0',
		total_tokens: '0',
		created_at: 0
	}
	list.push(item)
	let len = list.length > 1 ? list.length - 1 : 0;
	let objChatParams = {
		"type": 2,
		"inputs": {},
		"query": ask.value,
		"response_mode": "streaming",
		"user": "suguoyuan"
	}
	if (strFirstId.value) {
		objChatParams["conversation_id"] = strFirstId.value
	}
	// 请求大模型数据
	let env = import.meta.env,api = env.MODE == "development"? "/dev":"/prod";
	let url = api+"/admin/base/open/chat",token = eval(localStorage.getItem("token") || "");
	let data:any = await fetch(url,{method:"post", headers:{
		"Content-Type":"application/json",
		"Authorization":token
	},body:JSON.stringify(objChatParams)});
	const reader = data.body.getReader();
	let datas = "";
	while (true){
		const {done,value} = await reader.read();
		if(done){break};
		const decoder = new TextDecoder("utf-8");
		const data = decoder.decode(value);
		datas+=data;
	}
	let values = wholeToParse("["+datas.replace(/\n\ndata:/g,",").replace(/data:/g,"")+"]");
	let index = 0;
	let task = setInterval(() => {
		if(index>values.length-1){
			clearInterval(task);
			ask.value = "";
			isAsking.value = false;
			getFocus();
			return;
		}
		let res = values[index];
		let answer = [null,undefined,""].indexOf(res.answer)==-1? res.answer : commTip;
		list[len].answer += answer;
		strFirstId.value = res?.conversation_id;
		if(res?.metadata){
			console.log(res.metadata);
			list[len].list = res.metadata['retriever_resources'] ? res.metadata['retriever_resources'] : [];
			list[len].latency = res.metadata['usage'].latency;
			list[len].total_tokens = res.metadata['usage'].total_tokens;
		}
		scrollToBottom();
		index++;
	}, 30);
	// 请求大模型数据
	//let data = await service.base.open.chat(objChatParams).catch((error)=>{
	// 	console.log(error);
	// 	return;
	// });
	// let res = JSON.parse(data);
	// let str = res.answer;
	// let index = 0
	// let task = setInterval(() => {
	// 	index++;
	// 	list[len].answer = str.slice(0, index);
	// 	if (list[len].answer.length != index) {
	// 		clearInterval(task)
	// 		strFirstId.value = res?.conversation_id;
	// 		console.log("strFirstId", strFirstId.value)
	// 		list[len].list = res.metadata['retriever_resources'] ? res.metadata['retriever_resources'] : [];
	// 		list[len].latency = res.metadata['usage'].latency;
	// 		list[len].total_tokens = res.metadata['usage'].total_tokens;
	// 		ask.value = "";
	// 		isAsking.value = false;
	// 		scrollToBottom();
	// 		getFocus();
	// 	}
	// }, 30)
}
</script>
<style lang="scss" scoped>
.l-file {
	display: flex;
	padding: 20px 0 0 0;
}
.f-list {
	background-color: #fff;
	padding: 5px 10px;
	font-size: 12px;
	border-radius: 5px;
	margin-right: 10px;
	width: auto;
	white-space: nowrap;
	position: relative;
}
.f-list-content{
	cursor: pointer;
	span {
		position: relative;
		top: -3px;
	}
	.f-l-img {
		width: 16px;
		margin-right: 3px;
	}
}
.popover-title,.popover-content{
	padding: var(--el-popover-padding);
}
.popover-title{
	background: #f9fafb;
}
.f-l-position{
	padding: 10px 0;
	box-sizing: border-box;
	.f-l-position-container{
		display: inline-block;
		width: auto;
		min-width: 50px;
		padding: 5px;
		font-size: 14px;
		color: #666;
		line-height: 14px;
		box-sizing: border-box;
		border: 1px solid #dedede;
		border-radius: 5px;
		overflow: hidden;
		text-align: center;
		.f-l-icon{
            color:#333;
			padding-right: 5px;
		}
	}
}
.f-l-text{
	width: 100%;
	font-size: 14px;
	color: #666;
	height: auto;
	max-height: 180px;
	overflow: hidden;
	overflow-y: auto;
}
#content {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	justify-content: space-between;

	.list {
		background-color: #eee;
		color: #101828;
		padding: 10px;
		margin-bottom: 10px;
		height: 87%;
		width: 100%;
		overflow-y: auto;

		.l-item-left {
			display: flex;
			font-size: 15px;

			.l-img {
				width: 30px;
				height: 30px;
				padding: 10px;
				border-radius: 50%;
				background-color: rgb(117, 206, 244);
				margin-right: 10px;
				flex-shrink: 0;
			}

			.l-answer {
				background-color: #ddd;
				border-radius: 8px;
				padding: 15px;
				max-width: 90%;

				.loader {
					margin-top: 7px;
					width: 30px;
					aspect-ratio: 4;
					--_g: no-repeat radial-gradient(circle closest-side, #555 90%, #0000);
					background:
						var(--_g) 0% 50%,
						var(--_g) 50% 50%,
						var(--_g) 100% 50%;
					background-size: calc(100%/3) 100%;
					animation: l7 1s infinite linear;
				}

				@keyframes l7 {
					33% {
						background-size: calc(100%/3) 0%, calc(100%/3) 100%, calc(100%/3) 100%
					}

					50% {
						background-size: calc(100%/3) 100%, calc(100%/3) 0%, calc(100%/3) 100%
					}

					66% {
						background-size: calc(100%/3) 100%, calc(100%/3) 100%, calc(100%/3) 0%
					}
				}

				.bottom {
					padding-top: 10px;

					span {
						margin-bottom: -10px;
						background-color: #ddd;
						padding-right: 10px;
						font-size: 13px;
						color: #777;
					}

					.line {
						margin-top: -10px;
						border-bottom: solid 1px #ccc;
					}
				}
			}
		}

		.l-tip {
			padding-left: 60px;
			font-size: 12px;
			color: #777;
			margin-top: 5px;
			margin-bottom: 10px;
		}

		.l-item-right {
			display: flex;
			align-items: center;
			justify-content: end;
			margin-bottom: 10px;
			padding: 10px;
			font-size: 15px;

			.l-ask {
				.l-a-ask {
					background-color: #d0d0eb;
					padding-bottom: 15px;
					border-radius: 8px;
					padding: 15px;
				}
			}

			.l-a-img {
				width: 30px;
				height: 30px;
				padding: 10px;
				text-align: center;
				margin-left: 10px;
				border-radius: 50%;
				background-color: rgb(63, 32, 242);
				margin-right: 10px;
				flex-shrink: 0;
				color: #fff;
				font-size: 23px;
			}
		}

	}

	.ask {
		background-color: #eee;
		width: 100%;
		padding: 10px 0;
		display: flex;
		justify-content: center;
		align-items: center;
		height: 55px;
		position: relative;

		input {
			width: 96%;
			height: 45px;
			padding: 8px 20px;
			font-size: 15px;
			border: solid #ccc 1px;
			border-radius: 25px;
		}

		.send {
			height: 40px;
			width: 40px;
			border-radius: 50%;
			position: absolute;
			right: 25px;
			background-color: #ccc;
			display: flex;
			justify-content: center;
			align-items: center;
		}

		.send:hover {
			background-color: #777;
		}
	}
}
</style>
